package cn.qu.v1.platform.plugin.loader;

import cn.qu.v1.platform.inject.BeanContext;
import cn.qu.v1.platform.inject.BeanCreateException;
import cn.qu.v1.platform.plugin.Plugin;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 * Created by zh on 17/1/7.
 */
public class PluginManager implements Cloneable {
    private static final Logger logger = LoggerFactory.getLogger(PluginManager.class);

    private BeanContext context = BeanContext.create();
    private Map<String, Plugin> pluginMap = new LinkedHashMap<>();
    private List<Plugin> pluginList = new ArrayList<>();

    protected List<Plugin> sort(Map<String, Plugin> pluginMap) {
        List<Plugin> sortedList = new ArrayList<>();
        for (Map.Entry<String, Plugin> entry : pluginMap.entrySet()) {
            getBeanDepends(pluginMap, sortedList, entry.getKey());
        }
        return sortedList;
    }

    private void getBeanDepends(Map<String, Plugin> beanMap, List<Plugin> sortedList, String dependName) {
        Plugin bean = beanMap.get(dependName);
        String[] depends = bean.getMeta().getDependsOn();
        if (sortedList.contains(bean)) {
            logger.debug("依赖已存在:" + dependName);
            return;
        }
        for (String depend : depends) {
            if (!beanMap.containsKey(depend)) {
                logger.debug("依赖不存在:" + depend);
                continue;
            }
            if (sortedList.contains(beanMap.get(depend))) {
                logger.debug("依赖已存在:" + depend);
                continue;
            }

            getBeanDepends(beanMap, sortedList, depend);
        }
        sortedList.add(bean);
    }

    public PluginManager(String... pluginDirs) {
        Collection<File> pluginFiles = listPluginJarFiles(pluginDirs);

        for (File pluginFile : pluginFiles) {
            Plugin plugin = Plugin.create(pluginFile);

            pluginMap.put(plugin.getMeta().getPluginName(), plugin);
        }

        pluginList = sort(pluginMap);
        logger.info("插件加载顺序：");
        pluginList.forEach((plugin -> logger.info("插件名称:{}，版本:{}", plugin.getMeta().getPluginName(), plugin.getMeta().getVersionName())));

        ClassLoader parent = Thread.currentThread().getContextClassLoader();

        for (Plugin plugin : pluginList) {
            try {
                plugin.setParentClassLoader(parent);
                context.load(plugin);
            } catch (BeanCreateException e) {
                e.printStackTrace();
            } finally {
                parent = plugin.getClassLoader();
            }
        }
    }

    protected Collection<File> listPluginJarFiles(String... pluginDirs) {
        Collection<File> files = new LinkedList<>();

        for (String pluginDir : pluginDirs) {
            File file = new File(pluginDir);
            if (file.isDirectory()) {
                Collection<File> pluginJars = FileUtils.listFiles(file, new String[]{"jar"}, true);
                files.addAll(pluginJars);
            }
        }
        return files;
    }

    public Map<String, Plugin> getPluginMap() {
        return pluginMap;
    }
}
